"""
Namespace Manager for WebService

Handles creation and management of Kubernetes Namespace resources.
"""

import logging
from typing import Optional, Dict, Any
from kubernetes import client
from kubernetes.client.rest import ApiException
from common import consts


class NamespaceManagerError(Exception):
    """Namespace manager error"""
    pass


class NamespaceManager:
    """Kubernetes Namespace resource management"""
    
    def __init__(self):
        """Initialize namespace manager"""
        self.logger = logging.getLogger(__name__)
        self.v1 = client.CoreV1Api()
        
    def ensure_namespace_exists(self, namespace: str) -> bool:
        """
        Ensure namespace exists, create if it doesn't
        
        Args:
            namespace: Name of the namespace to ensure exists
            
        Returns:
            True if namespace exists or was created successfully
            
        Raises:
            NamespaceManagerError: If namespace creation fails
        """
        try:
            self.logger.info(f"Ensuring namespace {namespace} exists")
            
            # Check if namespace exists
            if self._namespace_exists(namespace):
                self.logger.info(f"Namespace {namespace} already exists")
                return True
            
            # Create namespace if it doesn't exist
            self.logger.info(f"Creating namespace {namespace}")
            self._create_namespace(namespace)
            self.logger.info(f"Successfully created namespace {namespace}")
            return True
            
        except Exception as e:
            error_msg = f"Failed to ensure namespace {namespace} exists: {e}"
            self.logger.error(error_msg)
            raise NamespaceManagerError(error_msg) from e
    
    def _namespace_exists(self, namespace: str) -> bool:
        """
        Check if namespace exists
        
        Args:
            namespace: Name of the namespace to check
            
        Returns:
            True if namespace exists, False otherwise
        """
        try:
            self.v1.read_namespace(name=namespace)
            return True
        except ApiException as e:
            if e.status == 404:
                return False
            # Re-raise other API exceptions
            raise
        except Exception as e:
            self.logger.error(f"Error checking if namespace {namespace} exists: {e}")
            return False
    
    def _create_namespace(self, namespace: str) -> None:
        """
        Create a namespace
        
        Args:
            namespace: Name of the namespace to create
            
        Raises:
            NamespaceManagerError: If namespace creation fails
        """
        try:
            # Build namespace object
            namespace_obj = self._build_namespace_object(namespace)
            
            # Create namespace in Kubernetes
            self.v1.create_namespace(body=namespace_obj)
            
        except ApiException as e:
            if e.status == 409:  # Conflict - namespace already exists
                self.logger.info(f"Namespace {namespace} already exists, skipping creation")
            else:
                error_msg = f"Failed to create namespace {namespace}: {e}"
                self.logger.error(error_msg)
                raise NamespaceManagerError(error_msg) from e
        except Exception as e:
            error_msg = f"Unexpected error creating namespace {namespace}: {e}"
            self.logger.error(error_msg)
            raise NamespaceManagerError(error_msg) from e
    
    def _build_namespace_object(self, namespace: str) -> Dict:
        """
        Build Kubernetes Namespace object
        
        Args:
            namespace: Name of the namespace
            
        Returns:
            Dictionary representing the namespace object
        """
        namespace_obj = {
            "apiVersion": "v1",
            "kind": "Namespace",
            "metadata": {
                "name": namespace,
                "labels": {
                    "managed-by": consts.APPLICATION_NAME
                },
                "annotations": {
                    "icecheng-reconciler/created": "true"
                }
            }
        }
        
        return namespace_obj
    
    def get_namespace_info(self, namespace: str) -> Optional[Dict[str, Any]]:
        """
        Get information about a namespace
        
        Args:
            namespace: Name of the namespace
            
        Returns:
            Dictionary with namespace information or None if not found
        """
        try:
            namespace_obj = self.v1.read_namespace(name=namespace)
            
            return {
                "name": namespace_obj.metadata.name,
                "created": namespace_obj.metadata.creation_timestamp,
                "labels": namespace_obj.metadata.labels or {},
                "annotations": namespace_obj.metadata.annotations or {},
                "status": namespace_obj.status.phase if namespace_obj.status else "Unknown"
            }
            
        except ApiException as e:
            if e.status == 404:
                return None
            self.logger.error(f"Failed to get namespace info {namespace}: {e}")
            return None
        except Exception as e:
            self.logger.error(f"Failed to get namespace info {namespace}: {e}")
            return None

    def delete_namespace(self, namespace: str) -> bool:
        """
        Delete a namespace
        
        Args:
            namespace: Name of the namespace to delete
            
        Returns:
            True if deletion was successful or namespace doesn't exist
            
        Raises:
            NamespaceManagerError: If namespace deletion fails
        """
        try:
            self.logger.info(f"Deleting namespace {namespace}")
            
            # Check if namespace exists first
            if not self._namespace_exists(namespace):
                self.logger.info(f"Namespace {namespace} doesn't exist, skipping deletion")
                return True
            
            # Delete namespace
            self.v1.delete_namespace(name=namespace)
            self.logger.info(f"Successfully deleted namespace {namespace}")
            return True
            
        except ApiException as e:
            if e.status == 404:
                self.logger.info(f"Namespace {namespace} doesn't exist, skipping deletion")
                return True
            else:
                error_msg = f"Failed to delete namespace {namespace}: {e}"
                self.logger.error(error_msg)
                raise NamespaceManagerError(error_msg) from e
        except Exception as e:
            error_msg = f"Unexpected error deleting namespace {namespace}: {e}"
            self.logger.error(error_msg)
            raise NamespaceManagerError(error_msg) from e
